﻿#include "Dispatcher.h"
#include <sys/epoll.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

#define Max 520
struct EpollData
{
	int epfd;
	struct epoll_event* events;
};
// static 表示局部函数
//这些函数都是要传入Dispatcher中
static void* epollInit();
static int epollAdd(struct Channel* channel, struct EventLoop* evLoop);
static int epollRemove(struct Channel* channel, struct EventLoop* evLoop);
static int epollModify(struct Channel* channel, struct EventLoop* evLoop);
static int epollDispatch(struct EventLoop* evLoop, int timeout); // 单位: s
static int epollClear(struct EventLoop* evLoop);
static int epollCtl(struct Channel* channel, struct EventLoop* evLoop, int op);

struct Dispatcher EpollDispatcher = {
	epollInit,
	epollAdd,
	epollRemove,
	epollModify,
	epollDispatch,
	epollClear
};//用函数指针初始化Dispatcher

//初始化epoll使用的数据
static void* epollInit()
{
	struct EpollData* data = (struct EpollData*)malloc(sizeof(struct EpollData));
	data->epfd = epoll_create(1);//大于0即可
	if (data->epfd == -1)
	{
		perror("epoll_create");
		exit(0);
	}
	//calloc 结合了 malloc 和 memset(0) 申请空间+置0     元素个数 , 元素空间大小
	data->events = (struct epoll_event*)calloc(Max, sizeof(struct epoll_event));

	return data;
}
//自定义epoll_ctl
static int epollCtl(struct Channel* channel, struct EventLoop* evLoop, int op)
{
	struct EpollData* data = (struct EpollData*)evLoop->dispatcherData;
	struct epoll_event ev;
	ev.data.fd = channel->fd;
	int events = 0;
	if (channel->events & ReadEvent)//此处events是自定义的
	{
		events |= EPOLLIN;//增加EPOLLIN监听事件
	}
	if (channel->events & WriteEvent)
	{
		events |= EPOLLOUT;//增加EPOLLOUT监听事件
	}
	ev.events = events;//设置ev.events,接着传入epoll_ctl 加入epoll监听树
	int ret = epoll_ctl(data->epfd, op, channel->fd, &ev);
	return ret;//返回epoll_ctl 操作结果
}
// 添加需要监听的文件描述符
static int epollAdd(struct Channel* channel, struct EventLoop* evLoop)
{
	int ret = epollCtl(channel, evLoop, EPOLL_CTL_ADD);
	if (ret == -1)
	{
		perror("epoll_crl add");
		exit(0);
	}
	return ret;
}
//删除监听的文件描述符
static int epollRemove(struct Channel* channel, struct EventLoop* evLoop)
{
	int ret = epollCtl(channel, evLoop, EPOLL_CTL_DEL);
	if (ret == -1)
	{
		perror("epoll_crl delete");
		exit(0);
	}
	// 通过 channel 释放对应的 TcpConnection 资源
	channel->destroyCallback(channel->arg);

	return ret;
}
//更新channel中对文件描述符监听的事件到epoll树中
static int epollModify(struct Channel* channel, struct EventLoop* evLoop)
{
	//修改描述符上设定的事件，需要用到由ev所指向的结构体中的信息。
	int ret = epollCtl(channel, evLoop, EPOLL_CTL_MOD);
	if (ret == -1)
	{
		perror("epoll_crl modify");
		exit(0);
	}
	return ret;
}
//使用epoll监控，分配任务
static int epollDispatch(struct EventLoop* evLoop, int timeout)//timeout 单位s
{
	struct EpollData* data = (struct EpollData*)evLoop->dispatcherData;
	int count = epoll_wait(data->epfd, data->events, Max, timeout * 1000);//单位ms  需要*1000
	for (int i = 0; i < count; ++i)
	{
		int events = data->events[i].events;
		int fd = data->events[i].data.fd;
		/*
		* EPOLLERR 对端断开连接
		* EPOLLHUP 对端断开连接，己方还在发数据，失败
		*/
		if (events & EPOLLERR || events & EPOLLHUP)//出现异常
		{
			// 对方断开了连接, 删除 fd
			// epollRemove(Channel, evLoop);
			continue;
		}
		if (events & EPOLLIN)
		{
			eventActivate(evLoop, fd, ReadEvent);
		}
		if (events & EPOLLOUT)
		{
			eventActivate(evLoop, fd, WriteEvent);
		}
	}
	return 0;
}

static int epollClear(struct EventLoop* evLoop)
{
	struct EpollData* data = (struct EpollData*)evLoop->dispatcherData;
	free(data->events);
	close(data->epfd);
	free(data);
	return 0;
}